package nobnak.study.gl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;

public class BezierCurveRenderer implements Renderer {
	public static final int SIZE_FLOAT = 4;
	public static final int SIZE_VERTEX_2D = 2;
	public static final int CAPACITY_VERTEX_BUFFER = 1024;
	public static final float SIZE_POINT = 5.0f;
	
	private FloatBuffer vertexBuffer;
	private List<VertexBufferElement> vertexBufferElements;
	
	
	public BezierCurveRenderer() {
		this.vertexBuffer = ByteBuffer.allocateDirect(CAPACITY_VERTEX_BUFFER * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
		this.vertexBufferElements = new ArrayList<VertexBufferElement>();
	}
	
	
	// Interfaces
	public static class VertexBufferElement {
		private int mode;
		private float[] vertices;
		private float[] colors;
		
		public VertexBufferElement(int mode, float[] vertices, float[] colors) {
			this.mode = mode;
			this.vertices = vertices;
			this.colors = colors;
		}
		
		public void glDrawArray(GL10 gl, int first) {
			gl.glColor4f(colors[0], colors[1], colors[2], colors[3]);
			gl.glDrawArrays(mode, first, count());
		}
		public int count() {
			return vertices.length / SIZE_VERTEX_2D;
		}
	}
	
	// Methods
	public void addVertexElement(VertexBufferElement element) {
		vertexBufferElements.add(element);
		updateVertexBuffer();
	}
	public void removeVertexElement(VertexBufferElement element) {
		vertexBufferElements.remove(element);
		updateVertexBuffer();
	}
	public void updateVertexBuffer() {
		vertexBuffer.clear();
		for (Iterator<VertexBufferElement> iter = vertexBufferElements.iterator(); iter.hasNext(); )
			vertexBuffer.put(iter.next().vertices);
		vertexBuffer.flip();
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glVertexPointer(SIZE_VERTEX_2D, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glPointSize(SIZE_POINT);
	}
	
	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(0, width, 0, height, -1, 1);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		gl.glColor4f(1, 1, 1, 1);
		int first = 0;
		for (Iterator<VertexBufferElement> iter = vertexBufferElements.iterator(); iter.hasNext(); ) {
			VertexBufferElement element = iter.next();
			element.glDrawArray(gl, first);
			first += element.count();
		}

		gl.glFlush();
	}

}
